package org.otarriinae.security.authenticate.config;

import org.otarriinae.kaptcha.service.KaptchaService;
import org.otarriinae.security.authenticate.filter.TokenLoginFilter;
import org.otarriinae.security.base.filter.TokenAuthenticationFilter;
import org.otarriinae.security.base.service.TokenManager;
import org.otarriinae.security.base.service.impl.TokenManagerImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Objects;

/**
 * @author xiejin
 * @since 1.0
 */

public abstract class AbstractAuthenticateWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final KaptchaService kaptchaService;

    protected AbstractAuthenticateWebSecurityConfig(KaptchaService kaptchaService) {
        this.kaptchaService = kaptchaService;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf().disable()
                .cors().disable()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                // 对于获取token的rest api要允许匿名访问
                .antMatchers("/login","/kaptcha").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().permitAll();
        httpSecurity
                .addFilterBefore(getTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new TokenLoginFilter(getTokenManager(), authenticationManager(), kaptchaService, getApplicationContext()), UsernamePasswordAuthenticationFilter.class);
        // 禁用缓存
        httpSecurity.headers().cacheControl();
    }

    private TokenManager getTokenManager() {
        return this.getApplicationContext().getBean(TokenManager.class);
    }


    private TokenAuthenticationFilter getTokenAuthenticationFilter() {
        return this.getApplicationContext().getBean(TokenAuthenticationFilter.class);
    }
    private RedisTemplate<String,String> getValueOperations() {
        return this.getApplicationContext().getBean(StringRedisTemplate.class);
    }
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(getUserDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 设置获取用户信息的service
     *
     */
    public  abstract UserDetailsService getUserDetailsService();

    /**
     * 设置redis 过期时间
     *
     */
    public  abstract Integer getExpiration();





    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public TokenManager tokenManager() {
        Integer expiration = getExpiration();
        if(Objects.isNull(expiration)){
            expiration = 60;
        }
        return new TokenManagerImpl(getValueOperations(), expiration);
    }

    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter(){
        return new TokenAuthenticationFilter(getValueOperations());
    }


}
